#include "client.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
#include <time.h>

typedef struct{
    bool connect;
    struct sockaddr_un addr;
    socklen_t len_t;
    int socket_fd;
    int fd;

    pthread_t rev_check_thread;
    pthread_t send_check_thread;
    bool exit_rev_thread;
    bool exit_send_thread;
    const uint16_t send_us;
    const uint16_t timeout_ms;
    bool should_send;
}Client_t;

static Client_t client = { \
    .connect = false, \
    .socket_fd = -1, \
    .fd = -1, \
    .exit_rev_thread = true, \
    .exit_send_thread = true, \
    .send_us = 20000, \
    .timeout_ms = 50, \
    .should_send = false \
};

static void Disconnect();
static int Write(uint8_t *buf, uint8_t len);
static int Read(uint8_t *buf, int len, uint16_t timeout_ms);
static void Client_Receive();

static void handle_exit(int sig)
{
    printf("\r\n");
    LOG_ERROR("Server receive signal %d",sig);
	if(sig == SIGINT)
	{
		LOG_INFO("You have press \"Ctrl+C\" to stop program!");
        exit(0);
    }
    // else if(sig == SIGPIPE)
	// {
	// 	LOG_INFO("continue communication!");
    //     if (Client_Connect() < 0)
    //     {
    //         sleep(1);
    //     }  
	// }
}


int Client_Init()
{
    struct sigaction act;

	act.sa_handler = handle_exit;
	act.sa_flags = SA_RESETHAND;
    sigaction(SIGINT,&act,NULL);
    act.sa_handler = SIG_IGN;
    sigaction(SIGPIPE,&act,NULL);

    // client.addr.sun_family = AF_UNIX;
    // strcpy(client.addr.sun_path, SOCKET_PATH);
    // client.len_t = sizeof(client.addr.sun_family) + sizeof(SOCKET_PATH);
    // 设置客户端参数  
    client.addr.sun_family = AF_UNIX;  
    strncpy(client.addr.sun_path, SOCKET_PATH, sizeof(client.addr.sun_path));  
    client.len_t = sizeof(client.addr);
    
    client.exit_rev_thread = false;
    client.exit_send_thread = false;
    pthread_create(&client.rev_check_thread, NULL, (void *(*) (void *))Client_Receive, NULL);
    pthread_create(&client.send_check_thread, NULL, (void *(*) (void *))Client_Send, NULL);
    
    return 0;
}

int Client_Connect()
{
    client.socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (client.socket_fd < 0)  
    {  
        LOG_ERROR("cannot create local socket, %s", strerror(errno));
        return -1;
    }
    else
    {
        // LOG_DEBUG("socket success:%d", client.socket_fd);
    }

    if (connect(client.socket_fd, (struct sockaddr *)&client.addr, client.len_t) < 0)
    {
        close(client.socket_fd);
        LOG_WARN("connect to server failed: %s", strerror(errno));

	    sleep(1);
        return -1;
    }
    LOG_DEBUG("connect to server success");

    client.fd = client.socket_fd;
    client.connect = true;

    return 0;
}

static void Disconnect()
{
    close(client.fd);
    client.fd = -1;
    client.connect = false;
    LOG_ERROR("Client deconnect with server!");
}

static int Write(uint8_t *buf, uint8_t len)
{
#if 0
    size_t left = size;

    while (client.fd > 0 && left > 0)
    {
        int bytes = send(client.fd, data, size, MSG_DONTWAIT);

        if (bytes <= 0)
        {
            if (errno != EINTR)
            {
                Disconnect();	
                return -1;
            }
        }

	    left -= bytes;
    }

    return size - left;
#endif
    int bytes_left = len;
	int written_bytes;

    if (client.fd < 0)
    {
        Client_Connect();
		return -1;
    }
    
    while (bytes_left > 0) 
	{ 
		/* 开始写*/ 
		written_bytes = send(client.fd, buf, bytes_left, MSG_DONTWAIT); 

		if (written_bytes <= 0) /* 出错了*/ 
		{ 
			if (errno == EINTR) /* 中断错误 我们继续写*/ 
			{
				LOG_ERROR("errno == EINTR continue");
				continue;
			}
			else if(errno == EAGAIN) /* EAGAIN : Resource temporarily unavailable*/ 
			{
				usleep(1000 * 100);//等待100毫秒，希望发送缓冲区能得到释放
				LOG_ERROR("errno == EAGAIN continue");
				continue;
			}
            else if(errno == EPIPE) /*断开连接后，产生这个信号*/
            {
                LOG_ERROR("errno = %d, strerror = %s" , errno, strerror(errno));
                Disconnect();
                return -1;
            }
			else /* 其他错误 没有办法,只好退了*/ 
			{
				LOG_ERROR("errno = %d, strerror = %s" , errno, strerror(errno));
				// sleep(1);
				return -1;
			}
		}
        else
        {
            bytes_left -= written_bytes; 
		    buf += written_bytes;/* 从剩下的地方继续写?? */ 
        }
	}

    

	return len;
}

static int Read(uint8_t *buf, int len, uint16_t timeout_ms)
{
    int i = 0;
	int ret;

#if 0
    if (client.fd > 0)
    {
        int rbytes = recv(client.fd, buf, len, MSG_DONTWAIT); 

        if (rbytes <= 0)
        { 
            if (errno != EINTR) 
            {
                LOG_ERROR("recv from server failed: %s", strerror(errno));
	            Disconnect();	
                return -1;
            }
        }
        else
        {
            cur_time = tUTCMSec();
            delta_time = cur_time - last_time;
            last_time = cur_time;

            if (delta_time > 25)
            {
                LOG_WARN("server uart read overtime %d ms.", delta_time);
            }
	    }
    }
#endif

    if (client.fd < 0)
	{
        LOG_ERROR("Read error:Client deconnect with server!");
		sleep(1);
		return -1;
	}

    while (i < len)
	{
        ret = recv(client.fd, buf + i, len - i, MSG_WAITALL);
        // ret = recv(client.fd, buf + i, len - i, MSG_DONTWAIT);

        if (ret < 0)
        {
            LOG_ERROR("errno = %d, strerror = %s" , errno, strerror(errno));
            if (EINTR == errno)
            {
                LOG_WARN("EINTR");
            }
            else if (EPIPE == errno)
            {
                LOG_WARN("EPIPE");
            }
            else if (EBADF == errno)
            {
                LOG_WARN("EBADF");
                Disconnect();
                return -1;
            }
            else if (EAGAIN == errno)
            {
                LOG_WARN("EAGAIN");
            }
            else
            {
                
            }

            // LOG_ERROR("clent read %d bytes failed, %s", len - i, strerror(errno));
            // return -1;
        }
        else 
        {
            i += ret;
        }

    }
    
    return i;
}

static void Client_Send_Judge()
{
    static clock_t last_clock = 0;
    double period;

    period = (double)(clock() - last_clock) / CLOCKS_PER_SEC;
    uint64_t handle_time = (uint64_t)(period * 1000000); // to us.
    if (handle_time < client.send_us)
    {
        usleep((__useconds_t)(client.send_us - handle_time));
    }	
    else
    {
        LOG_ERROR("serial handle_time %ld, period %f.", handle_time, period);
        // usleep(10000);
    }

    client.should_send = true;
    last_clock = clock();
}

void Client_Send()
{
    CPU_BINDING(1);
    SET_THREAD_SCHEDULE;

    char buf[SOCKET_BYTE_CNT] = {0};
    int64_t cur_time;
	int64_t last_time;
    cur_time = tUTCMSec();
    last_time = cur_time;
    int delta_time;
    uint8_t counter = 0;
    uint32_t info = 0;

    LOG_INFO("Enter to Client_Send");
    while (!client.exit_send_thread)
    {
        Client_Send_Judge();

        if (client.should_send)
        {
            if (Write(buf, SOCKET_BYTE_CNT) < 0)
            {
                continue;
            }
            // if (client.connect) DateDebug("send data", buf, SOCKET_BYTE_CNT);

            info++;
            buf[0] = 0xAA;
            buf[1] = 0x55;
            buf[2] = 0x01;
            buf[3] = info & 0xff;
            buf[4] = (info >> 8) & 0xff;
            buf[5] = (info >> 16) & 0xff;
            buf[6] = (info >> 24) & 0xff;
            buf[SOCKET_BYTE_CNT-2] = 0xCC;
            buf[SOCKET_BYTE_CNT-1] = 0x33;
                
        #ifdef SOCKET_SNED_OVERTIME_DEBUG
            cur_time = tUTCMSec();
            delta_time = cur_time - last_time;
            if (delta_time < 18 || delta_time > 22)
            {
                LOG_ERROR("client send overtime %d ms.", delta_time);
            }
            else
            {
                LOG_DEBUG("client send overtime %d ms.", delta_time);
            }
            last_time = cur_time;
        #endif

            if (client.connect) ++counter;
            if (50 == counter)
            {
                counter = 0;
                LOG_DEBUG("Server have send!");
            }
            client.should_send = false;
        }
    }
    
}

static void Client_Receive()
{
    CPU_BINDING(1);
    SET_THREAD_SCHEDULE;
    
    char buf[SOCKET_BYTE_CNT] = {0};
    int64_t cur_time;
	int64_t last_time;
    cur_time = tUTCMSec();
    last_time = cur_time;
    int delta_time;

    LOG_INFO("Enter to Client_Receive");
    while (!client.exit_rev_thread)
    {
        if (Read(buf, SOCKET_BYTE_CNT, client.timeout_ms) < 0)
            continue;
        // if (client.connect) DateDebug("receive data", buf, SOCKET_BYTE_CNT);

    #ifdef SOCKET_REC_OVERTIME_DEBUG
        cur_time = tUTCMSec();
        delta_time = cur_time - last_time;
        if (delta_time < 18 || delta_time > 22)
        {
            LOG_ERROR("client read overtime %d ms.", delta_time);
        }
        else
        {
            LOG_DEBUG("client read overtime %d ms.", delta_time);
        }
        last_time = cur_time;
    #endif
    }
    LOG_INFO("Exit to Client_Receive");
}

